package org.easyspring.aop.aspectWeaver;

import org.easyspring.aop.ProxyCreator;
import org.easyspring.aop.annotation.Aspect;
import org.easyspring.aop.annotation.Order;
import org.easyspring.aop.aspect.AspectInfo;
import org.easyspring.aop.aspect.AspectListExecutor;
import org.easyspring.aop.aspect.DefaultAspect;
import org.easyspring.core.BeanContainer;
import org.easyspring.util.ValidationUtil;

import java.lang.annotation.Annotation;
import java.util.*;

public class AspectWeaver {
    private BeanContainer beanContainer;

    public AspectWeaver(BeanContainer beanContainer) {
        this.beanContainer = BeanContainer.getInstance();
    }

    /**
     * Aop TODO【005】【★★★★★】
     */
    public void doAop() {
        //1.获取所有的切面类
        Set<Class<?>> aspectSet = beanContainer.getClassByAnnotation(Aspect.class);
        //2.将切面类按照不同的织入目标进行切分
        Map<Class<? extends Annotation>, List<AspectInfo>> categorizedMap = new HashMap<>();
        if (ValidationUtil.isEmpty(aspectSet)) {
            return;
        }
        for (Class<?> aspectClass : aspectSet
        ) {
            if (verifyAspect(aspectClass)) {
                categorizeAspect(categorizedMap, aspectClass);
            } else {
                throw new RuntimeException("@Aspect and @Order have not been added to the Aspect class," +
                        "or Aspect class does not extend from DefaultAspect,or the value in Aspect Tag equals @Aspect");
            }
        }
        //3.按照不同的织入目标分别去按序织入Aspect的逻辑
        if (ValidationUtil.isEmpty(categorizedMap)) {
            return;
        }
        for (Class<? extends Annotation> category : categorizedMap.keySet()
        ) {
            weaveByCategory(category, categorizedMap.get(category));
        }
    }

    private void weaveByCategory(Class<? extends Annotation> category, List<AspectInfo> aspectInfos) {
        //1.获取被代理类的集合
        Set<Class<?>> classSet = beanContainer.getClassByAnnotation(category);
        if (ValidationUtil.isEmpty(classSet)) {
            return;
        }
        //2.遍历被代理类,分别为每个被代理类生成动态代理实例
        for (Class<?> targetClass:classSet
             ) {
            //创建动态代理对象
            AspectListExecutor aspectListExecutor = new AspectListExecutor(targetClass,aspectInfos);
            Object proxyBean = ProxyCreator.createProxy(targetClass, aspectListExecutor);
            //3.将动态代理对象实例添加到容器里，取代未被代理前的类实例
            beanContainer.addBean(targetClass,proxyBean);
        }
    }

    private void categorizeAspect(Map<Class<? extends Annotation>, List<AspectInfo>> categorizedMap, Class<?> aspectClass) {
        Order orderTag = aspectClass.getAnnotation(Order.class);
        Aspect aspectTag = aspectClass.getAnnotation(Aspect.class);
        DefaultAspect aspect = (DefaultAspect) beanContainer.getBean(aspectClass);
        AspectInfo aspectInfo = new AspectInfo(orderTag.value(), aspect);
        if(!categorizedMap.containsKey(aspectTag.value())){
            //如果织入的joinpoint第一次出现，则以该joinpoint为key，以新创建的List<AspectInfo>为value
            List<AspectInfo> aspectInfoList = new ArrayList<>();
            aspectInfoList.add(aspectInfo);
            categorizedMap.put(aspectTag.value(),aspectInfoList);
        }else{
            //如果织入的joinpoint不是i第一次出现，则往joinpoint对应的value里添加Aspect逻辑
            List<AspectInfo> aspectInfoList = categorizedMap.get(aspectTag.value());
            aspectInfoList.add(aspectInfo);
        }
    }

    /**
     * 校验切面注解
     * 1.框架中一定要遵守给Aspect类添加@Aspect和@Order标签的规范
     * 2.同时必须继承自DefaultAspect.class
     * 3.@Aspect的属性值不能是它本身
     *
     * @param aspectClass
     * @return
     */
    private boolean verifyAspect(Class<?> aspectClass) {
        return aspectClass.isAnnotationPresent(Aspect.class)
                && aspectClass.isAnnotationPresent(Order.class)
                && DefaultAspect.class.isAssignableFrom(aspectClass)
                && aspectClass.getAnnotation(Aspect.class).value() != Aspect.class;
    }
}
